#include "Parcel.h"

//#include <stdio.h>
#define ALOGV(...) //{printf(__VA_ARGS__); printf("\n");}
#define LOG_ALLOC(...) // {printf(__VA_ARGS__); printf("\n");}

// 4字节对齐
#define PAD_SIZE_UNSAFE(s) (((s) + 3) & ~3)

#define SIZE_T_MAX INT32_MAX
#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(x)

static size_t pad_size(size_t s)
{
    if (s > (SIZE_T_MAX - 3)) {
        abort();
    }
    return PAD_SIZE_UNSAFE(s);
}

namespace android {

// 构造/析构函数相关 ------------------------------------------------------------------------------------------

Parcel::Parcel()
{
    LOG_ALLOC("Parcel@%p: constructing", this);
    initState();
}

Parcel::~Parcel()
{
    freeDataNoInit();
    LOG_ALLOC("Parcel@%p: destroyed", this);
}

// 成员变量相关 ----------------------------------------------------------------------------------------------

const uint8_t* Parcel::data() const
{
    return mData;
}

size_t Parcel::dataSize() const
{
    return (mDataSize > mDataPos ? mDataSize : mDataPos);
}

size_t Parcel::dataAvail() const
{
    size_t result = dataSize() - dataPosition();
    if (result > INT32_MAX) {
        abort();
    }
    return result;
}

size_t Parcel::dataPosition() const
{
    return mDataPos;
}

size_t Parcel::dataCapacity() const
{
    return mDataCapacity;
}

status_t Parcel::setDataSize(size_t size)
{
    if (size > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    status_t err;
    err = continueWrite(size);
    if (err == NO_ERROR) {
        mDataSize = size;
        ALOGV("setDataSize Setting data size of Parcel@%p to %zu", this, mDataSize);
    }
    return err;
}

void Parcel::setDataPosition(size_t pos) const
{
    if (pos > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        abort();
    }

    mDataPos = pos;
}

status_t Parcel::setDataCapacity(size_t size)
{
    if (size > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    if (size > mDataCapacity)
        return continueWrite(size);
    return NO_ERROR;
}

void Parcel::freeData()
{
    freeDataNoInit();
    initState();
}

// 写入操作相关 ----------------------------------------------------------------------------------------------

namespace {

    template <typename T>
    status_t writeByteVectorInternal(Parcel* parcel, const std::vector<T>& val)
    {
        status_t status;
        if (val.size() > (size_t)std::numeric_limits<int32_t>::max()) {
            status = BAD_VALUE;
            return status;
        }

        int32_t size = val.size() * sizeof(T);
        status = parcel->writeInt32(size);
        if (status != OK) {
            return status;
        }

        void* data = parcel->writeInplace(size);
        if (!data) {
            status = BAD_VALUE;
            return status;
        }

        memcpy(data, val.data(), size);
        return status;
    }

} // namespace

status_t Parcel::write(const void* data, size_t len)
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    void* const d = writeInplace(len);
    if (d) {
        memcpy(d, data, len);
        return NO_ERROR;
    }
    return mError;
}

// 设置下次读写位置，返回本次读写位置
void* Parcel::writeInplace(size_t len)
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return NULL;
    }

    const size_t padded = pad_size(len);

    // sanity check for integer overflow
    if (mDataPos + padded < mDataPos) {
        return NULL;
    }

    if ((mDataPos + padded) <= mDataCapacity) {
    restart_write:
        //printf("Writing %ld bytes, padded to %ld\n", len, padded);
        uint8_t* const data = mData + mDataPos;

        // Need to pad at end?
        if (padded != len) {
#if defined(BIG_ENDIAN) && BIG_ENDIAN
            static const uint32_t mask[4] = {
                0x00000000, 0xffffff00, 0xffff0000, 0xff000000
            };
#else
            static const uint32_t mask[4] = {
                0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
            };
#endif
            //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
            //    *reinterpret_cast<void**>(data+padded-4));
            // padded != len
            // eg. len=3, padded=4, finally  value &= 0x00ffffff
            *reinterpret_cast<uint32_t*>(data + padded - 4) &= mask[padded - len];
        }

        finishWrite(padded);
        return data;
    }

    status_t err = growData(padded);
    if (err == NO_ERROR)
        goto restart_write;
    return NULL;
}

// ----------------------

status_t Parcel::writeInt8(const int8_t val)
{
    return writeAligned((const int32_t)val);
}

status_t Parcel::writeInt16(const int16_t val)
{
    return writeAligned((const int32_t)val);
}

status_t Parcel::writeInt32(const int32_t val)
{
    return writeAligned(val);
}

status_t Parcel::writeInt64(const int64_t val)
{
    return writeAligned(val);
}

status_t Parcel::writeFloat(const float val)
{
    return writeAligned(val);
}

status_t Parcel::writeDouble(const double val)
{
    return writeAligned(val);
}

status_t Parcel::writeString(const std::string& str)
{
    status_t err = writeInt32(str.length());
    if (err == NO_ERROR) {
        uint8_t* data = (uint8_t*)writeInplace(str.length());
        if (data) {
            memcpy(data, str.c_str(), str.length());
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}

status_t Parcel::writeInt8Vector(const std::vector<int8_t>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeInt16Vector(const std::vector<int16_t>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeFloatVector(const std::vector<float>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeDoubleVector(const std::vector<double>& val)
{
    return writeByteVectorInternal(this, val);
}

status_t Parcel::writeStringVector(const std::vector<std::string>& val)
{
    if (val.size() > (size_t)std::numeric_limits<int32_t>::max()) {
        return BAD_VALUE;
    }

    status_t status = this->writeInt32(static_cast<int32_t>(val.size()));

    if (status != OK) {
        return status;
    }

    for (const auto& item : val) {
        status = writeString(item);

        if (status != OK) {
            return status;
        }
    }

    return OK;
}

// 读取操作相关 ----------------------------------------------------------------------------------------------

namespace {

    template <typename T>
    status_t readByteVectorInternal(const Parcel* parcel,
        std::vector<T>* val)
    {
        val->clear();

        int32_t size;
        status_t status = parcel->readInt32(&size);

        if (status != OK) {
            return status;
        }

        if (size < 0) {
            status = UNEXPECTED_NULL;
            return status;
        }
        if (size_t(size) > parcel->dataAvail()) {
            status = BAD_VALUE;
            return status;
        }

        T* data = const_cast<T*>(reinterpret_cast<const T*>(parcel->readInplace(size)));
        if (!data) {
            status = BAD_VALUE;
            return status;
        }
        val->reserve(size);
        val->insert(val->end(), data, data + size / sizeof(T));

        return status;
    }

} // namespace

status_t Parcel::read(void* outData, size_t len) const
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    if ((mDataPos + pad_size(len)) >= mDataPos // 没溢出
        && (mDataPos + pad_size(len)) <= mDataSize // 足够数据
        && len <= pad_size(len)) { // 没溢出
        memcpy(outData, mData + mDataPos, len);
        mDataPos += pad_size(len);
        ALOGV("read Setting data pos of Parcel@%p to %zu", this, mDataPos);
        return NO_ERROR;
    }
    return NOT_ENOUGH_DATA;
}

// 设置下次读写位置，返回本次读写位置
const void* Parcel::readInplace(size_t len) const
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return NULL;
    }

    if ((mDataPos + pad_size(len)) >= mDataPos // 没溢出
        && (mDataPos + pad_size(len)) <= mDataSize // 足够数据
        && len <= pad_size(len)) { // 没溢出
        const void* data = mData + mDataPos;
        mDataPos += pad_size(len);
        ALOGV("readInplace Setting data pos of Parcel@%p to %zu", this, mDataPos);
        return data;
    }
    return NULL;
}

// ----------------------

status_t Parcel::readInt8(int8_t* pArg) const
{
    int32_t tmp = 0;
    status_t ret = readInt32(&tmp);
    *pArg = int8_t(tmp);
    return ret;
}

status_t Parcel::readInt16(int16_t* pArg) const
{
    int32_t tmp = 0;
    status_t ret = readInt32(&tmp);
    *pArg = int16_t(tmp);
    return ret;
}

status_t Parcel::readInt32(int32_t* pArg) const
{
    return readAligned(pArg);
}

status_t Parcel::readInt64(int64_t* pArg) const
{
    return readAligned(pArg);
}

status_t Parcel::readFloat(float* pArg) const
{
    return readAligned(pArg);
}

status_t Parcel::readDouble(double* pArg) const
{
    return readAligned(pArg);
}

status_t Parcel::readString(std::string* pArg) const
{
    int32_t size = readInt32();
    if (size >= 0 && size < INT32_MAX) {
        const char* data = reinterpret_cast<const char*>(readInplace(size));
        if (data) {
            pArg->assign(data, size);
            return NO_ERROR;
        }
    }
    *pArg = std::string();
    return UNEXPECTED_NULL;
}

status_t Parcel::readInt8Vector(std::vector<int8_t>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readInt16Vector(std::vector<int16_t>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readFloatVector(std::vector<float>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readDoubleVector(std::vector<double>* val) const
{
    return readByteVectorInternal(this, val);
}

status_t Parcel::readStringVector(std::vector<std::string>* val) const
{
    int32_t size;
    status_t status = this->readInt32(&size);

    if (status != OK) {
        return status;
    }

    if (size < 0) {
        return UNEXPECTED_NULL;
    }

    if (val->max_size() < static_cast<size_t>(size)) {
        return NO_MEMORY;
    }

    val->resize(static_cast<size_t>(size));

    if (val->size() < static_cast<size_t>(size)) {
        return NO_MEMORY;
    }

    for (auto& v : *val) {
        status = readString(&v);

        if (status != OK) {
            return status;
        }
    }

    return OK;
}

int32_t Parcel::readInt32() const
{
    return readAligned<int32_t>();
}

// 辅助函数相关 ----------------------------------------------------------------------------------------------

void Parcel::initState()
{
    LOG_ALLOC("Parcel@%p: initState", this);
    mError = NO_ERROR;
    mData = 0;
    mDataSize = 0;
    mDataCapacity = 0;
    mDataPos = 0;
    ALOGV("initState Setting data size of Parcel@%p to %zu", this, mDataSize);
    ALOGV("initState Setting data pos of Parcel@%p to %zu", this, mDataPos);
}

void Parcel::freeDataNoInit()
{
    if (mData) {
        LOG_ALLOC("Parcel@%p: freeing with %zu capacity", this, mDataCapacity);
        free(mData);
    }
}

// ---------------------

status_t Parcel::finishWrite(size_t len)
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    //printf("Finish write of %d\n", len);
    mDataPos += len;
    ALOGV("finishWrite Setting data pos of Parcel@%p to %zu", this, mDataPos);
    if (mDataPos > mDataSize) {
        mDataSize = mDataPos;
        ALOGV("finishWrite Setting data size of Parcel@%p to %zu", this, mDataSize);
    }
    //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
    return NO_ERROR;
}

status_t Parcel::continueWrite(size_t desired)
{
    if (desired > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    if (mData) {
        // We own the data, so we can just do a realloc().
        if (desired > mDataCapacity) {
            uint8_t* data = (uint8_t*)realloc(mData, desired);
            if (data) {
                LOG_ALLOC("Parcel@%p: continue from %zu to %zu capacity", this, mDataCapacity, desired);
                mData = data;
                mDataCapacity = desired;
            } else {
                mError = NO_MEMORY;
                return NO_MEMORY;
            }
        } else {
            if (mDataSize > desired) {
                mDataSize = desired;
                ALOGV("continueWrite Setting data size of Parcel@%p to %zu", this, mDataSize);
            }
            if (mDataPos > desired) {
                mDataPos = desired;
                ALOGV("continueWrite Setting data pos of Parcel@%p to %zu", this, mDataPos);
            }
        }

    } else {
        // This is the first data.  Easy!
        uint8_t* data = (uint8_t*)malloc(desired);
        if (!data) {
            mError = NO_MEMORY;
            return NO_MEMORY;
        }

        LOG_ALLOC("Parcel@%p: allocating with %zu capacity", this, desired);

        mData = data;
        mDataSize = mDataPos = 0;
        ALOGV("continueWrite Setting data size of Parcel@%p to %zu", this, mDataSize);
        ALOGV("continueWrite Setting data pos of Parcel@%p to %zu", this, mDataPos);
        mDataCapacity = desired;
    }

    return NO_ERROR;
}

status_t Parcel::growData(size_t len)
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return BAD_VALUE;
    }

    size_t newSize = ((mDataSize + len) * 3) / 2;
    // 避免频繁分配
    if (newSize < 128) {
        newSize = 128;
    }
    return (newSize <= mDataSize) // 溢出
        ? (status_t)NO_MEMORY
        : continueWrite(newSize);
}

// ---------------------

template <class T>
status_t Parcel::writeAligned(T val)
{
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));

    if ((mDataPos + sizeof(val)) <= mDataCapacity) {
    restart_write:
        *reinterpret_cast<T*>(mData + mDataPos) = val;
        return finishWrite(sizeof(val));
    }

    status_t err = growData(sizeof(val));
    if (err == NO_ERROR)
        goto restart_write;
    return err;
}

template <class T>
status_t Parcel::readAligned(T* pArg) const
{
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));

    if ((mDataPos + sizeof(T)) <= mDataSize) {
        const void* data = mData + mDataPos;
        mDataPos += sizeof(T);
        *pArg = *reinterpret_cast<const T*>(data);
        return NO_ERROR;
    } else {
        return NOT_ENOUGH_DATA;
    }
}

template <class T>
T Parcel::readAligned() const
{
    T result;
    if (readAligned(&result) != NO_ERROR) {
        result = 0;
    }

    return result;
}

} // namespace android
